import {Component, OnInit, ViewChild} from '@angular/core';
import {SocketService} from '../../services/socket.service';
import {any} from 'codelyzer/util/function';
declare let RTCPeerConnection: any;
@Component({
  selector: 'app-one2ontchat',
  templateUrl: './one2ontchat.component.html',
  styleUrls: ['./one2ontchat.component.css']
})
export class One2ontchatComponent implements OnInit {

  mediaConstraints={
    "audio":true,
    "video":true
  }
  pc:any;
  transceiver:any;
  webcamstream:any;
  targetUsername:string | undefined;
  username:string | undefined;
  ws:any;


  @ViewChild("me") me: any;
  @ViewChild("remote") remote:any;


  constructor(private socket:SocketService) { }

  ngOnInit(): void {
    this.createPeerConnection();
  }


  createPeerConnection(){

    const iceConfiguration={
      iceServers:[
        {urls: 'stun:192.168.1.34:3478?transport=udp'},
        {
          urls:'turn:192.168.1.34:3478?transport=udp',
          username:'avenue',
          credential:'65222062',
          credentialType: 'password'
        }
      ]
    }
    this.pc=new RTCPeerConnection(iceConfiguration);
    //console.dir(this.pc);
    this.pc.onconnectionstatechange= (event:any)=>this.handleConnectionStateChange(event);
    this.pc.onicecandidateerror=(event:any)=>this.handleIceCandidateError(event);
    this.pc.onicecandidate=(event:any)=>this.handleICECandidateEvent(event);
    this.pc.oniceconnectionstatechange=(event:any)=>this.handleICEConnectionStateChangeEvent(event);
    this.pc.onicegatheringstatechange=(event:any)=>this.handleICEGatheringStateChangeEven(event);
    this.pc.onsignalingstatechange=(event:any)=>this.handleSignalingStateChangeEvent(event);
    this.pc.onnegotiationneeded=(event:any)=>this.handleNegotiationNeededEvent(event);
    this.pc.ontrack=(event:any)=>this.handleTrackEven(event);
  }

  handleConnectionStateChange(event:any){

    console.warn("Connection State Changed to"+this.pc.connectionState);
    switch (this.pc.connectionState){
      case 'connected':
        //试试吧这里注释了，可以不指定turn 地址不
        const config=this.pc.getConfiguration();
        console.log("Current Configuration")
        console.dir(config);
        break;
      case 'disconnected':

        break

      case 'failed':
        console.warn("Connection Failed now restart ICE");
        this.pc.restartIce();
        setTimeout(()=>{
          if(this.pc.iceConnectionState!== 'connected'){
            console.error("restartIce failed! close video call!" + "Connection state:" + this.pc.connectionState)
        this.closeVideoCall();
          }
        },1000*10)

        break;
    }

  }

  handleIceCandidateError(event:any){
    console.error("ICE Candidate Error, errorCode"+event.errorCode+"errorText"+event.errorText);

  }

  handleICECandidateEvent(event:any){

    console.log("handle Ice Candidate")
    //console.dir(event);
    console.log("ICE Candidate已然生成,准备发送Candicate信息到信令系统")
    if(event.candidate){
      console.log("*** Outgoing ICE candidate: "+event.candidate.candidate);
      console.log("ICE Candidate已然生成,准备发送Candicate信息到信令系统")
      // //服务端交互第2步  发送候选者信息到服务器
      let candidatestr=JSON.stringify(event.candidate);
      let body={
        type: "new-ice-candidate",
           target: this.targetUsername,
           candidate: candidatestr
      }
      this.socket.sendMessage(body);

    }

  }

  handleICEConnectionStateChangeEvent(event:any){
    console.warn("*** ICE connection state changed to "+this.pc.iceConnectionState);
  }

  handleICEGatheringStateChangeEven(event:any){
    console.warn("*** ICE gathering state changed to: " + this.pc.iceGatheringState);
  }

  handleSignalingStateChangeEvent(event:any){
    console.warn("*** WebRTC signaling state changed to: " + this.pc.signalingState);
    switch (event.signalingState){
      case 'closed':
        this.closeVideoCall();
        break;
    }

  }


  async handleNegotiationNeededEvent(event:any){
    console.log("*** Negotiation needed");

    try {
      if (this.pc.signalingState != 'stable') {
        console.warn('-- The connection isn\'t stable yet; postponing...');
        return;
      }
      console.log('---> Setting local description to the offer');

      await this.pc.setLocalDescription();
      this.pc.setLocalDescription()
        .then((description:any)=>{
          console.log('---> Sending the offer to the remote peer');
          console.log("准备发送到服务端的SDP Description"+description);
          console.dir(this.pc.localDescription.sdp);
        // 实锤啦 这个是第一步
          if(this.pc.localDescription.sdp){
            let body={
              name: this.username,
              target: this.targetUsername,
              type: "video-offer",
              sdp: this.pc.localDescription
            }
            this.sendMessage(body);
          }
        });
    } catch (e) {
      console.log("*** The following error occurred while handling the negotiationneeded event:");
    }

  }


  handleTrackEven(event:any){
    console.warn("*** Track event  捕获到轨道");

    try {
      this.remote.nativeElement.srcObject = event.streams[0];
    } catch (e) {
      console.error("播放视频异常");
      console.error(e);
    }


  }

  closeVideoCall(){
    if(this.pc){
      console.warn("--> Closing the peer connection");
      this.pc.ontrack=null;
      this.pc.onicecandidate=null;
      this.pc.oniceconnectionstatechange=null;
      this.pc.onsignalingstatechange=null;
      this.pc.onicegatheringstatechange=null;
      this.pc.onnotificationneeded=null;

      this.pc.getTransceivers().forEach((transceiver:any)=>{
        transceiver.stop();
      })
      if(this.me.srcObject){
        this.me.pause();
        this.me.srcObject.getTracks().forEach((track:any)=>{
          track.stop();
        });
      }
    this.pc.close();
      this.pc=null;
      this.webcamstream=null;
    }


  }


  async handleVideoOfferMsg(msg:any){


    if(!this.pc){
     await this.createPeerConnection();
    }

    if(this.pc.signalingState!='stable'){
      console. log("  - But the signaling state isn't stable, so triggering rollback");
      let remotesdp=JSON.parse(msg.sdp);
      await  Promise.all([
        this.pc.setLocalDescription({"type":"rollback"}),
       this.pc.setRemoteDescription(new RTCSessionDescription(remotesdp))
      ]);
      return;
    }else{
      //console.log("要添加的SDP"+msg.sdp);
      let remotesdp=JSON.parse(msg.sdp);
      await this.pc.setRemoteDescription(remotesdp);
    }
  //  用来回传自己的图像
    if(!this.webcamstream){

      try {
         await navigator.mediaDevices.getUserMedia(this.mediaConstraints)
          .then((stream:MediaStream)=>{
            this.webcamstream=stream;
          })
      } catch (e) {
        this.handleGetUserMediaError(e)
        return;
      }
    }
    this.me.nativeElement.srcObject=this.webcamstream;

    try {
      this.webcamstream.getTracks().forEach(
        this.transceiver = (track: any) => {
          this.pc.addTransceiver(track, {streams: [this.webcamstream]});
        }
      )
    } catch (e) {
       this.handleGetUserMediaError(e)
    }

    console.log("---> Creating and sending answer to caller");
    await this.pc.setLocalDescription()
      .then(()=>{
        if(this.pc.localDescription.sdp){
          let body={
            name: this.username,
            target: this.targetUsername,
            type: "video-answer",
            sdp: this.pc.localDescription
          }
          this.sendMessage(body);

        }


      })



  }

  handleGetUserMediaError(e:any){
    console.error(e);
    switch(e.name) {
      case "NotFoundError":
        alert("Unable to open your call because no camera and/or microphone" +
          "were found.");
        break;
      case "SecurityError":
      case "PermissionDeniedError":
        break;
      default:
        alert("Error opening your camera and/or microphone: " + e.message);
        break;
    }

    this.closeVideoCall();
  }


 async invite(){
    console.log("Starting to prepare an invitation");
   navigator.mediaDevices.getUserMedia(this.mediaConstraints)
     .then((stream:any)=>{
       this.me.nativeElement.srcObject=stream;
       this.webcamstream=stream;
       try {
         this.webcamstream.getTracks().forEach(this.transceiver = (track: any) => {
           this.pc.addTransceiver(track, {streams: [this.webcamstream]});
         })
       } catch (e) {
         this.handleGetUserMediaError(e);
       }

     })
  }



  connect(){
    this.socket.connectServer(this.username!)
      .subscribe((event:any)=>{
        //console.dir(event);
          const jsonMessage = JSON.parse(event);
          switch (jsonMessage.type) {

            case "video-offer":
              this.handleVideoOfferMsg(jsonMessage);
              break;
            case "new-ice-candidate":
              this.handleNewICECandidateMsg(jsonMessage);
              break;
            case "video-answer":
              this.handleVideoAnswerMsg(jsonMessage)
              break;
          }
      },(err)=>{
        console.dir(err);
        },()=>{
        console.log("连接关闭")
        }
      )

  }

  sendMessage(message:any){
    this.socket.sendMessage(message);
  }

  offSocket(){
   this.socket.close();
  }

  async handleNewICECandidateMsg(msg:any){

    if(!this.pc){
      await this.createPeerConnection();
    }

    try {
      console.log("接收到的iceCandidate"+msg.candidate);
      let candidate=JSON.parse(msg.candidate)   ;

      if(this.pc.remoteDescription){
        console.log("准备使用的ICEcandidate");
        console.dir(candidate);
        //this.pc.addIceCandidate(new  RTCIceCandidate(candidate));
        this.pc.addIceCandidate(candidate);
      }
    } catch (e) {
      console.warn('添加Candidate 发生异常');
      console.error(e);
    }

  }



  async  handleVideoAnswerMsg(msg:any) {
    console.log("*** Call recipient has accepted our call");
    console.warn("收到应答");


    let sdp=JSON.parse(msg.sdp);

    await this.pc.setRemoteDescription(sdp).catch((error:any)=>{
      console.log("")
      console.dir(error);
    });
  }

}
